#include "asgkaCreater.h"
#include "global.h"
#include "common.h"
#include "asgka_space.h"
#include "asgka_network.h"
#include "messageSinglePubKey.h"
#include "messageCiphertext.h"
#include "messagetype.h"

#include <iostream>
using namespace std;

asgkaCreater::asgkaCreater()
:asgkaBase(),
 m_my_priR(NULL),
 m_my_priO(NULL),
 m_my_priX(NULL),
 m_my_pubH(NULL),
 m_my_pubR(NULL),
 m_my_pubA(NULL),
 m_my_priR_length(0)
{}

asgkaCreater::asgkaCreater(singleGroup *group)
:asgkaBase(group),
 m_my_priR(NULL),
 m_my_priO(NULL),
 m_my_priX(NULL),
 m_my_pubH(NULL),
 m_my_pubR(NULL),
 m_my_pubA(NULL),
 m_my_priR_length(0)
{
}

asgkaCreater::~asgkaCreater()
{
	if (m_my_priR != NULL)
		asgka_free(m_my_priR);
	if (m_my_priO != NULL)
		asgka_free(m_my_priO);
	if (m_my_priX != NULL)
		asgka_free(m_my_priX);
	if (m_my_pubH != NULL)
		asgka_free(m_my_pubH);
	if (m_my_pubR != NULL)
		asgka_free(m_my_pubR);
	if (m_my_pubA != NULL)
		asgka_free(m_my_pubA);

	std::map<std::string, asgka_element>::iterator it = m_my_pubO.begin();
	while (it != m_my_pubO.end())
	{
		if (it->second != NULL)
			asgka_free(it->second);
		m_my_pubO.erase(it++);
	}
}

void asgkaCreater::publicMyPubH() const
{
	// Generate message object
	const std::map<std::string, singleMember *> *temp = m_group->getAddrofMemberlist();
	messageBase *message = new messageSinglePubKey(m_group->getGroupName(), m_my_pubH, NET_MESSAGE_KEY_PUB_H);
	std::map<std::string, singleMember *>::const_iterator it = temp->begin();
	for (; it != temp->end(); it++)
	{
		if (localname.compare(it->first) == 0)
			continue;
		cout << "send H to " << it->second->getMemberName() << endl;
		sendMessageToMember_tcp(message, it->second);
	}
	delete message;
}

void asgkaCreater::publicMyPubKeysGroup() const
{
	// Send R and A to the group leader and send oij to the certain member
	// Send R and A

	if (localname.compare(m_group->getGroupName()) != 0)
	{
		std::string leadername = m_group->getGroupLeader()->getMemberName();
		messageBase *messagePubR = new messageSinglePubKey(m_group->getGroupName(), m_my_pubR, NET_MESSAGE_KEY_PUB_R);
		messageBase *messagePubA = new messageSinglePubKey(m_group->getGroupName(), m_my_pubA, NET_MESSAGE_KEY_PUB_A);
		std::map<std::string, singleMember *>::const_iterator it = m_group->getAddrofMemberlist()->find(leadername);
		if (it != m_group->getAddrofMemberlist()->end())
		{
			sendMessageToMember_tcp(messagePubR, it->second);
			sendMessageToMember_tcp(messagePubA, it->second);
		}
		delete messagePubR;
		delete messagePubA;
	}

	// Send oij
	std::map<std::string, singleMember *>::const_iterator it = m_group->getAddrofMemberlist()->begin();
	for (; it != m_group->getAddrofMemberlist()->end(); it++)
	{
		if (localname.compare(it->first) == 0)
			continue;
		std::map<std::string, asgka_element>::const_iterator aeit = m_my_pubO.find(it->first);
		if (aeit != m_my_pubO.end())
		{
			messageBase *messagePubO = new messageSinglePubKey(m_group->getGroupName(), aeit->second, NET_MESSAGE_KEY_PUB_O);
			sendMessageToMember_tcp(messagePubO, it->second);
			delete messagePubO;
		}
	}
}

void asgkaCreater::computeMyGroupKeyR()
{
	memcpy(m_my_groupKeyR, m_my_pubR, LENGTH);

	const std::map<std::string, singleMember *> *member_list = m_group->getAddrofMemberlist();
	std::map<std::string, singleMember *>::const_iterator it =  member_list->begin();
	for (; it !=  member_list->end(); it++)
	{
		if (localname.compare(it->first) == 0)
			continue;
		computeGroupKey(m_my_groupKeyR, m_my_groupKeyR, 
			it->second->getMemberpubR(m_group->getGroupName()), LENGTH, GROUPKEYR);
	}
}

void asgkaCreater::computeMyGroupKeyA()
{
	memcpy(m_my_groupKeyA, m_my_pubA, LENGTH);

	const std::map<std::string, singleMember *> *member_list = m_group->getAddrofMemberlist();
	std::map<std::string, singleMember *>::const_iterator it =  member_list->begin();
	for (; it !=  member_list->end(); it++)
	{
		if (localname.compare(it->first) == 0)
			continue;
		computeGroupKey(m_my_groupKeyA, m_my_groupKeyA, 
			it->second->getMemberpubA(m_group->getGroupName()), LENGTH, GROUPKEYA);
	}
}

void asgkaCreater::generateMyOwnKeys()
{
	asgka_malloc(m_my_priR);
	asgka_malloc(m_my_priO);
	asgka_malloc(m_my_priX);
	asgka_malloc(m_my_pubH);
	asgka_malloc(m_my_pubR);
	asgka_malloc(m_my_pubA);

	generateKeys(m_my_priR, m_my_priX, m_my_priO, m_my_pubR, m_my_pubA, m_my_pubH, LENGTH, &m_my_priR_length);

	m_group->setPubH(m_my_pubH);
	m_group->setPriR(m_my_priR);
	m_group->setPriX(m_my_priX);
}

void asgkaCreater::computeMyPubKeysGroupO()
{
	// Traversal the map and compute 
	std::map<std::string, singleMember *>::const_iterator it = m_group->getAddrofMemberlist()->begin();

	for (; it != m_group->getAddrofMemberlist()->end(); it++)
	{
		if (localname.compare(it->first) == 0)
			continue;
		asgka_element temp;
		asgka_malloc(temp);
		asgka_element pubH;
		pubH = it->second->getMemberpubH(m_group->getGroupName());
		computeOtherPubO(temp, m_my_priX, m_my_priR, pubH, LENGTH); 
		m_my_pubO.insert(stoevalType(it->first, temp));
	}
}

void asgkaCreater::computeMyDecryptKey()
{
	std::map<std::string, singleMember *>::const_iterator it = m_group->getAddrofMemberlist()->begin();
	asgka_malloc(m_my_decrypt_key);
	memcpy(m_my_decrypt_key, m_my_priO, LENGTH);

	for (; it != m_group->getAddrofMemberlist()->end(); it++)
	{
		if (localname.compare(it->first) == 0)
			continue;
		asgka_element myO;
		myO = it->second->getMemberXigama(m_group->getGroupName());
		computeDecryptKey(m_my_decrypt_key, m_my_decrypt_key, myO, LENGTH);
	}
}

